﻿using LpbPrj.Client.Data;
using LpbPrj.Client.Event;
using LpbPrj.Client.Views;
using Microsoft.Extensions.Logging;
using Prism.Commands;
using Prism.Events;
using Prism.Ioc;
using Prism.Mvvm;
using Prism.Regions;
using Prism.Services.Dialogs;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing.Text;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using Unity;

namespace LpbPrj.Client.ViewModels
{
    public class NavigationBaseViewModel : GlobalBaseViewModel, INavigationAware
    {
        /// <summary>
        /// 是否重现Navigation，重现（返回True）还是新建（返回False），默认false
        /// </summary>
        public bool ReviewNavigation { get; protected set; } = false;
        /// <summary>
        /// 导航记录
        /// </summary>
        protected IRegionNavigationJournal RegionNavigationJournal { get; set; } = null;
        /// <summary>
        /// 目标地址
        /// </summary>
        protected string NavigatedUrl;

        public NavigationBaseViewModel(IEventAggregator eventAggregator, IRegionManager regionManager, IDialogService dialogService)
            : base(eventAggregator, regionManager, dialogService)
        {
            ReviewNavigation = true;
        }

        /// <summary>
        /// 控件View是重现（返回True）还是新建（返回False）
        /// </summary>
        /// <param name="navigationContext"></param>
        /// <returns></returns>
        public bool IsNavigationTarget(NavigationContext navigationContext)
        {
            System.Diagnostics.Debug.WriteLine("IsNavigationTarget");
            return ReviewNavigation;
        }

        /// <summary>
        /// 导航到此View时执行
        /// </summary>
        /// <param name="navigationContext"></param>
        public virtual void OnNavigatedTo(NavigationContext navigationContext)
        {
            RegionNavigationJournal = navigationContext.NavigationService.Journal;

            _logger?.LogInformation($"********************{this.GetType()}--_logger--OnNavigatedTo***********************");
            logger?.LogInformation($"********************{this.GetType()}--logger--OnNavigatedTo***********************");
            Logger?.LogInformation($"********************{this.GetType()}--Logger--OnNavigatedTo***********************");
        }

        /// <summary>
        /// 从此View导航出去的时候执行
        /// </summary>
        /// <param name="navigationContext"></param>
        public void OnNavigatedFrom(NavigationContext navigationContext)
        {
            System.Diagnostics.Debug.WriteLine("OnNavigatedFrom");

            //释放所有事件,可以通过ReviewNavigation来判断是不是常驻的
            if (ReviewNavigation == false)
            {
                for (int i = 0; i < SubscriptionTokenList.Count; i++)
                {
                    _eventAggregator.GetEvent<MessageSentEvent>().Unsubscribe(SubscriptionTokenList[i]);
                }
                System.Diagnostics.Debug.WriteLine("EventUnsubscribe");

                worker?.Dispose();
                worker = null;
            }
        }


    }

    public class DialogBaseViewModel : GlobalBaseViewModel, IDialogAware
    {
        /// <summary>
        /// 按键操作
        /// </summary>
        public DelegateCommand<KeyEventArgs> KeyDownCommand =>
            new Lazy<DelegateCommand<System.Windows.Input.KeyEventArgs>>(() => new DelegateCommand<System.Windows.Input.KeyEventArgs>(p =>
            {
                KeyDownEvent(p);
            })).Value;

        public DialogBaseViewModel(IEventAggregator eventAggregator, IRegionManager regionManager, IDialogService dialogService)
            : base(eventAggregator, regionManager, dialogService)
        {
            ScopedRegionManager = regionManager.CreateRegionManager();
            _scopedRegionManager.RegisterViewWithRegion("DialogLoadingRegion", typeof(DialogWaitingView));
        }

        public event Action<IDialogResult> RequestClose;
        public string Title { get; protected set; } = GlobalData.Config.SoftTitle;

        /// <summary>
        /// 先于MainLoadedEvent执行
        /// </summary>
        /// <param name="parameters"></param>
        public virtual void OnDialogOpened(IDialogParameters parameters)
        {
            System.Diagnostics.Debug.WriteLine("OnDialogOpened");

            _logger?.LogInformation($"********************{this.GetType()}--_logger--OnDialogOpened***********************");
            logger?.LogInformation($"********************{this.GetType()}--logger--OnDialogOpened***********************");
            Logger?.LogInformation($"********************{this.GetType()}--Logger--OnDialogOpened***********************");
        }

        protected virtual void KeyDownEvent(KeyEventArgs eventArgs) { }

        protected override void MainClickEvent(string p)
        {
            if (string.IsNullOrEmpty(p)) return;

            //取消或者关闭
            if (p.Equals("Cancel"))
            {
                var dialogResult = new DialogResult(ButtonResult.Cancel);
                RequestClose?.Invoke(dialogResult);
                return;
            }

            //保存或者确定
            if (p.Equals("OK"))
            {
                var dialogResult = new DialogResult(ButtonResult.OK);
                SaveDialog(ref dialogResult);
                RequestClose?.Invoke(dialogResult);
                return;
            }
        }

        public virtual bool CanCloseDialog()
        {
            return true;
        }

        public virtual void SaveDialog(ref DialogResult dialogResult) { }

        public void OnDialogClosed()
        {
            System.Diagnostics.Debug.WriteLine("OnDialogClosed");

            //释放所有事件，验证
            for (int i = 0; i < SubscriptionTokenList.Count; i++)
            {
                _eventAggregator.GetEvent<MessageSentEvent>().Unsubscribe(SubscriptionTokenList[i]);
            }
            System.Diagnostics.Debug.WriteLine("EventUnsubscribe");

            worker?.Dispose();
            worker = null;
        }

        /// <summary>
        /// 对话框局部的管理器
        /// </summary>
        public IRegionManager ScopedRegionManager { get => _scopedRegionManager; set => SetProperty(ref _scopedRegionManager, value); }
        protected IRegionManager _scopedRegionManager;

        /// <summary>
        /// 等待窗口提示语
        /// </summary>
        protected string _loadingTip = "Waiting";
        public string LoadingTip { get => _loadingTip; set => SetProperty(ref _loadingTip, value); }
        /// <summary>
        /// 等待窗口提示语
        /// </summary>
        protected int _zIndex = int.MaxValue;
        public int ZIndex { get => _zIndex; set => SetProperty(ref _zIndex, value); }

        /// <summary>
        /// 等待窗口是否显示
        /// </summary>
        protected Visibility _loadingVisibility = Visibility.Collapsed;
        public Visibility LoadingVisibility { get => _loadingVisibility; set => SetProperty(ref _loadingVisibility, value); }

        protected void DoUiActionWithWaiting(Action uiAction, Action nextUiAction = null)
        {
            LoadingVisibility = Visibility.Visible;
            ZIndex = 1;

            taskFactory.StartNew(() =>
            {
                try
                {
                    uiAction.Invoke();
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex.Message);
                    //DataCenterFactory.Instantiation().Logger.Error($"DoActionWithWaiting Invoke Error, {ex.Message}");
                    //DataCenterFactory.Instantiation().Logger.Error($"DoActionWithWaiting Invoke Error, {ex.StackTrace}");
                }

            }, appExitToken.Token).ContinueWith(t =>
            {
                if (nextUiAction != null)
                {
                    try
                    {
                        var taskNext = App.Current.Dispatcher.BeginInvoke(nextUiAction);
                        taskNext.Wait();
                    }
                    catch (Exception ex)
                    {
                        System.Diagnostics.Debug.WriteLine(ex.Message);
                        //DataCenterFactory.Instantiation().Logger.Error($"DoActionWithWaiting nextUiAction Invoke Error, {ex.Message}");
                        //DataCenterFactory.Instantiation().Logger.Error($"DoActionWithWaiting nextUiAction Invoke Error, {ex.StackTrace}");
                    }
                }
                LoadingVisibility = Visibility.Collapsed;
                ZIndex = int.MaxValue;
            });
        }


    }

    public class GlobalBaseViewModel : BindableBase
    {
        /// <summary>
        /// 取消触摸屏下滚动条到头后窗体抖动
        /// </summary>
        public DelegateCommand<ManipulationBoundaryFeedbackEventArgs> ManipulationBoundaryFeedbackCommand =>
            new Lazy<DelegateCommand<ManipulationBoundaryFeedbackEventArgs>>(() => new DelegateCommand<ManipulationBoundaryFeedbackEventArgs>(p =>
            {
                /*
                WPF,用ScrollViewer控件，触屏开发，当滑动到最后时会使整个窗体弹跳一下

                原因是因为ScrollViewer触屏操作原生支持惯性，ScrollViewer中的内容滚动到边界是会自动触发Window Bounce（窗体弹跳），

                以叫做Panning Feedback（拖动回馈）。

                欲取消这种效果，办法如下：

                1.转给ScrollViewer注册ManipulationBoundaryFeedback事件

                2.在事件中书写：e.Handled = true; 即可。

                private void listview_ManipulationBoundaryFeedback(object sender, ManipulationBoundaryFeedbackEventArgs e)
                {
                    e.Handled = true;
                }
                */

                p.Handled = true;

            })).Value;

        /// <summary>
        /// 窗口加载
        /// </summary>
        public DelegateCommand<RoutedEventArgs> MainLoadedCommand =>
            new Lazy<DelegateCommand<RoutedEventArgs>>(() => new DelegateCommand<RoutedEventArgs>(p =>
            {
                MainLoadedEvent(p);
            })).Value;

        /// <summary>
        /// 窗口释放
        /// </summary>
        public DelegateCommand<RoutedEventArgs> MainUnloadedCommand =>
            new Lazy<DelegateCommand<RoutedEventArgs>>(() => new DelegateCommand<RoutedEventArgs>(p =>
            {
                MainUnloadedEvent(p);

            })).Value;

        /// <summary>
        /// 主窗口大小变化
        /// </summary>
        public DelegateCommand<SizeChangedEventArgs> SizeChangedCommand =>
            new Lazy<DelegateCommand<SizeChangedEventArgs>>(() => new DelegateCommand<SizeChangedEventArgs>(p =>
            {
                SizeChangedEvent(p);
            })).Value;

        /// <summary>
        /// 界面按钮命令
        /// </summary>
        public DelegateCommand<string> MainClickCommand =>
            new Lazy<DelegateCommand<string>>(() => new DelegateCommand<string>(p =>
            {
                if (string.IsNullOrEmpty(p)) return;
                MainClickEvent(p);
            })).Value;


        /// <summary>
        /// 线程取消标记，程序退出时使用
        /// </summary>
        protected CancellationTokenSource appExitToken = new CancellationTokenSource();
        /// <summary>
        /// Task工厂
        /// </summary>
        protected TaskFactory taskFactory = new TaskFactory();
        /// <summary>
        /// 所有线程
        /// </summary>
        protected List<Task> taskList = new List<Task>();
        /// <summary>
        /// 所有事件
        /// </summary>
        protected List<SubscriptionToken> SubscriptionTokenList = new List<SubscriptionToken>();

        protected readonly IEventAggregator _eventAggregator;
        protected readonly IRegionManager _regionManager;
        protected readonly IDialogService _dialogService;
        protected readonly Logger<GlobalBaseViewModel> _logger;
        protected BackgroundWorker worker;

        /// <summary>
        /// 方法注入
        /// 属性logger则通过方法Initialize初始化，该方法上应用了特性InjectionMethodAttribute，意味着这是一个注入方法在IOLViewModel对象被IoC容器创建的时候会被自动调用
        /// 此方法只能在构造函数执行完使用
        /// </summary>
        [InjectionMethod]
        public void Initalize(Logger<GlobalBaseViewModel> logger)
        {
            this.logger = logger;
            Debug.WriteLine($"********************{this.GetType()}方法注入***********************");
        }
        protected Logger<GlobalBaseViewModel> logger;

        /// <summary>
        /// 使用属性注入获得 logger
        /// 此方法只能在构造函数执行完使用
        /// </summary>
        [Dependency]
        public Logger<GlobalBaseViewModel> Logger { get; set; }

        public GlobalBaseViewModel(IEventAggregator eventAggregator, IRegionManager regionManager, IDialogService dialogService)
        {
            GuidKey = Guid.NewGuid().ToString();

            _eventAggregator = eventAggregator;
            _regionManager = regionManager;
            _dialogService = dialogService;

            //此方法可以在所有viewModel中使用
            _logger = ContainerLocator.Container.Resolve<Logger<GlobalBaseViewModel>>();

            ComboBoxData = GetLocalItem();
            ComboBoxItem = ComboBoxData.FirstOrDefault(p => p.Name.Equals(GlobalData.Config.Font));

            eventAggregator.GetEvent<MessageSentEvent>()
                .Subscribe(obj =>
                {
                    if (obj.MsgParam != null)
                    {
                        var font = obj.MsgParam.GetValue<FontItem>("Param");
                        FontName = font.Name;
                        GlobalData.Config.Font = font.Name;
                    }
                }, ThreadOption.UIThread, false, (filter) => filter.MsgKey.Equals(EventKey.Font));

            var versionInfo = FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly().Location);
            SoftVersion = versionInfo.FileVersion;

            worker = new BackgroundWorker();
            worker.WorkerReportsProgress = true;
            worker.WorkerSupportsCancellation = true;
            worker.DoWork += Worker_DoWork;
            worker.ProgressChanged += Worker_ProgressChanged;
            worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
        }

        /// <summary>
        /// 字体
        /// </summary>
        public string FontName { get => _FontName; set => SetProperty(ref _FontName, value); }
        protected string _FontName = GlobalData.Config.Font;

        /// <summary>
        /// 软件标题
        /// </summary>
        public string SoftTitle { get; private set; } = GlobalData.Config.SoftTitle;
        /// <summary>
        /// 软件版本号
        /// </summary>
        public string SoftVersion { get; private set; }

        /// <summary>
        /// guid唯一标识
        /// </summary>
        public string GuidKey { get; private set; }

        /// <summary>
        /// 界面加载
        /// </summary>
        /// <param name="eventArgs"></param>
        protected virtual void MainLoadedEvent(RoutedEventArgs eventArgs) { }

        /// <summary>
        /// 界面释放
        /// </summary>
        /// <param name="eventArgs"></param>
        protected virtual void MainUnloadedEvent(RoutedEventArgs eventArgs) { }

        /// <summary>
        /// 界面大小改变
        /// </summary>
        /// <param name="args"></param>
        protected virtual void SizeChangedEvent(SizeChangedEventArgs args) { }

        /// <summary>
        /// 界面按钮命令
        /// </summary>
        /// <param name="p"></param>
        protected virtual void MainClickEvent(string p) { }

        /// <summary>
        /// 所有字体
        /// </summary>
        public List<FontItem> ComboBoxData { get; set; } = new List<FontItem>();
        /// <summary>
        /// 选中的字体
        /// </summary>
        protected FontItem _comboBoxItem;
        public FontItem ComboBoxItem
        {
            get => _comboBoxItem; set
            {
                SetProperty(ref _comboBoxItem, value);
                _eventAggregator.GetEvent<MessageSentEvent>().Publish(new MessageEvent(EventKey.Font, value));
            }
        }
        /// <summary>
        /// 获取本地字体列表
        /// </summary>
        private List<FontItem> GetLocalItem()
        {
            List<FontItem> fontItems = new List<FontItem>();

            System.Drawing.FontFamily[] families = null;
            try
            {
                InstalledFontCollection fontCollection = new InstalledFontCollection();
                families = fontCollection.Families;
            }
            catch (Exception)
            {
                families = new System.Drawing.FontFamily[0];
            }
            foreach (System.Drawing.FontFamily family in families)
            {
                FontItem fontLocalItem = new FontItem();
                fontLocalItem.Name = family.Name;
                fontItems.Add(fontLocalItem);
            }

            return fontItems;
        }

        /// <summary>
        /// 异步等待执行
        /// </summary>
        /// <param name="action"></param>
        /// <param name="waitingTitle"></param>
        /// <param name="nextUiAction"></param>
        protected void DoActionWithWaiting(Action action, string waitingTitle = null, Action nextUiAction = null)
        {
            {
                var param = new NavigationParameters();
                param.Add("Visible", true);
                param.Add("LoadingTip", string.IsNullOrEmpty(waitingTitle) ? "Waiting" : waitingTitle);
                _eventAggregator.GetEvent<MessageSentEvent>().Publish(new MessageEvent(EventKey.LoadingControlVisible, param));
            }

            taskFactory.StartNew(() =>
            {
                try
                {
                    action.Invoke();
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex.Message);
                    _logger.LogError($"DoActionWithWaiting Invoke Error, {ex.Message}");
                    _logger.LogError($"DoActionWithWaiting Invoke Error, {ex.StackTrace}");
                }

            }, appExitToken.Token).ContinueWith(t =>
            {
                if (nextUiAction != null)
                {
                    try
                    {
                        var taskNext = App.Current.Dispatcher.BeginInvoke(nextUiAction);
                        taskNext.Wait();
                    }
                    catch (Exception ex)
                    {
                        System.Diagnostics.Debug.WriteLine(ex.Message);
                        _logger.LogError($"DoActionWithWaiting nextUiAction Invoke Error, {ex.Message}");
                        _logger.LogError($"DoActionWithWaiting nextUiAction Invoke Error, {ex.StackTrace}");
                    }

                }
                var param = new NavigationParameters();
                param.Add("Visible", false);
                param.Add("LoadingTip", string.IsNullOrEmpty(waitingTitle) ? "Waiting" : waitingTitle);
                _eventAggregator.GetEvent<MessageSentEvent>().Publish(new MessageEvent(EventKey.LoadingControlVisible, param));
            });
        }


        protected virtual void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
                MessageBox.Show(e.Cancelled.ToString());
            }
            else if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message);
            }
            else
            {
                BackgroundWorkerResult workerItem = e.Result as BackgroundWorkerResult;
                if (workerItem != null)
                {
                    System.Diagnostics.Debug.WriteLine(workerItem.Index);
                }

                var param = new NavigationParameters();
                param.Add("Visible", false);
                param.Add("LoadingTip", "Waiting");
                _eventAggregator.GetEvent<MessageSentEvent>().Publish(new MessageEvent(EventKey.LoadingControlVisible, param));
            }
        }
        protected virtual void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e) { }
        protected virtual void Worker_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorkerArgument WorkAction = e.Argument as BackgroundWorkerArgument;
            if (worker.CancellationPending) return;

            try
            {
                WorkAction.WorkAction?.Invoke();
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);
                _logger.LogError($"Worker_DoWork Invoke Error, {ex.Message}");
                _logger.LogError($"Worker_DoWork Invoke Error, {ex.StackTrace}");
            }

            BackgroundWorkerResult workerItem = new BackgroundWorkerResult();
            workerItem.Success = true;
            workerItem.Index = 10;
            workerItem.DateTimeCur = DateTime.Now;
            e.Result = workerItem;
        }
        protected virtual void Worker_Run(Func<int> workAction, string waitingTitle = null)
        {
            {
                var param = new NavigationParameters();
                param.Add("Visible", true);
                param.Add("LoadingTip", string.IsNullOrEmpty(waitingTitle) ? "Waiting" : waitingTitle);
                _eventAggregator.GetEvent<MessageSentEvent>().Publish(new MessageEvent(EventKey.LoadingControlVisible, param));
            }
            worker.RunWorkerAsync(new BackgroundWorkerArgument(workAction));
        }


    }

    /// <summary>
    /// 字体结构体
    /// </summary>
    public class FontItem
    {
        /// <summary>
        /// 字体名称
        /// </summary>
        public string Name { get; set; }
    }


    public class BackgroundWorkerResult
    {
        public bool Success { get; set; }
        public int Index { get; set; }
        public DateTime DateTimeCur { get; set; }

    }
    public class BackgroundWorkerArgument
    {
        public Func<int> WorkAction { get; set; }

        public BackgroundWorkerArgument(Func<int> workAction)
        {
            this.WorkAction = workAction;
        }
    }
}
